// 函数

// 一、函数的参数

// 定义函数
function foo(x, y) {
    console.log(x, y);
}

// 调用函数
foo("hello", "jayjun");


// 1、参数默认值

// ES5 方式：不严谨
function foo2(x, y) {
    y = y || "world"
    console.log(x, y);
}

foo2("hello");
foo2("hello", 0); // hello world

// ES6 方式：通常把带有参数默认值的参数放到后面
function foo3(x, y = "world") {
    console.log(x, y);
}

foo3("hello");
foo3("hello", 0); // hello 0
foo3("hello", undefined); // hello world

// 2、与解构赋值结合

function ajax(url, {
    method = "GET",
    headers = {},
    body = ""
} = {}) {
    console.log(method);
}

ajax("https://www.baidu.com"); // GET

ajax("https://www.baidu.com", {
    method: "POST"
}); // POST

// 3、length 属性：没有设置参数默认值的参数个数

function bar(z, x = 1, y = 2) {
    console.log(x, y, z);
}

console.log(bar.length); // 1

// 4、参数作用域

{
    let x = 1;
    function demo(x, y = x) {
        console.log(y);
    }

    demo(2); // 2
}

{
    // 作用域链：当在JS中使用一个变量的时候，首先JS会尝试在当前作用域下去寻找该变量，如果没有找到，再到它上一层作用域寻找。
    // 以此类推直到找到该变量为止。
    let x = 1;
    function demo(y = x) {
        let x = 2;
        console.log(y);
    }
    demo() // 1
}

{
    // 作用域链：当在JS中使用一个变量的时候，首先JS会尝试在当前作用域下去寻找该变量，如果没有找到，再到它上一层作用域寻找。
    // 以此类推直到找到该变量为止，如果最后也没找到，直接报错！
    /*
    function demo(y = x) {
        let x = 2;
        console.log(y);
    }
    */
    // demo() // Uncaught ReferenceError: x is not defined
}

// 二、扩展运算符与rest（剩余）参数

// ...

// 1、扩展运算符：将数组元素按照,进行处理

{
    // 解构赋值
    function test([a, b, c]) {
        console.log(a, b, c);
    }
    
    let arr = [1, 2, 3];
    test(arr);
}

{
    // ...
    function test(a, b, c) {
        console.log(a, b, c);
    }
    
    let arr = [1, 2, 3];
    
    test(...arr); // ...[1, 2, 3] => 1, 2, 3
}

// 例子：合并数组

{
    // ES5 方式
    let arr1 = [1, 2, 3];
    let arr2 = [4, 5, 6];
    // [1, 2, 3, 4, 5, 6];

    Array.prototype.push.apply(arr1, arr2);
    console.log(arr1);
}

{
    // ES6 方式
    let arr1 = [1, 2, 3];
    let arr2 = [4, 5, 6];
    // [1, 2, 3, 4, 5, 6];

    arr1.push(...arr2); // [4, 5, 6] => 4, 5, 6
    console.log(arr1);

    let word = "jayjun";
    console.log(...word);
}

// 2、rest参数（剩余参数）

// 例子：计算函数所有参数的和
{
    // ES5 方式：使用 arguments 结合 forEach 会报错
    function foo() {
        // arguments 参数数组，这是一个伪数组
        console.log(arguments);
        let result = 0;
        arguments.forEach(function(value) {
            result += value
        });
        return result;
    }

    // foo(); // Uncaught TypeError: arguments.forEach is not a function
}

{
    // ES5 方式：使用 arguments 结合 Array 对象提供的原型方法 forEach
    function foo() {
        let result = 0;
        Array.prototype.forEach.call(arguments, function(value) {
            result += value;
        });
        return result;
    }

    console.log(foo());
    console.log(foo(1));
    console.log(foo(1, 2));
    console.log(foo(1, 2, 3, 5, 7, 89));
}


{
    // ES6 方式：使用rest参数（...）
    function foo(...args) {
        // console.log(args);
        let result = 0;
        args.forEach(function(value) {
            result += value;
        })
        return result;
    }

    console.log(foo()); 
    console.log(foo(1));
    console.log(foo(1, 2));
    console.log(foo(1, 2, 3, 5, 7, 89));
}

let [x, ...y] = [1, 2, 3, 4];
console.log(x, y);